package cn.lqz.bucttrain.service.impl;

import cn.lqz.bucttrain.enums.OrderStatusEnum;
import cn.lqz.bucttrain.enums.ResponseCodeEnum;
import cn.lqz.bucttrain.enums.SeatTypeEnum;
import cn.lqz.bucttrain.enums.UserStatusEnum;
import cn.lqz.bucttrain.exceptions.BaseException;
import cn.lqz.bucttrain.mapper.OrderMapper;
import cn.lqz.bucttrain.mapper.PassengerMapper;
import cn.lqz.bucttrain.mapper.RouteMapper;
import cn.lqz.bucttrain.mapper.UserMapper;
import cn.lqz.bucttrain.pojo.dto.*;
import cn.lqz.bucttrain.pojo.entity.Order;
import cn.lqz.bucttrain.pojo.entity.Passenger;
import cn.lqz.bucttrain.pojo.entity.Route;
import cn.lqz.bucttrain.pojo.entity.User;
import cn.lqz.bucttrain.pojo.vo.OrderStatisticMoneyVO;
import cn.lqz.bucttrain.pojo.vo.OrderStatisticNumVO;
import cn.lqz.bucttrain.pojo.vo.OrderVO;
import cn.lqz.bucttrain.pojo.vo.PageResultVO;
import cn.lqz.bucttrain.service.OrderService;
import cn.lqz.bucttrain.utils.StringUtils;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.io.InputStream;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 订单service
 */
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
    @Resource
    private OrderMapper orderMapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private PassengerMapper passengerMapper;
    @Resource
    private RouteMapper routeMapper;

    /**
     * 加载或查询订单
     * @param orderPageQueryDTO
     * @return
     */
    @Override
    public PageResultVO loadOrderList(OrderPageQueryDTO orderPageQueryDTO) {
        log.info("加载或查询订单列表：{}",orderPageQueryDTO);
        PageHelper.startPage(orderPageQueryDTO.getPageNo(),orderPageQueryDTO.getPageSize());
        Page<OrderVO> page = orderMapper.findBatch(orderPageQueryDTO);
        return new PageResultVO(orderPageQueryDTO.getPageNo(),orderPageQueryDTO.getPageSize(),page.getTotal(),page.getResult());
    }

    /**
     * 添加订单
     * @param orderCreateDTO
     */
    @Override
    public void addOrder(OrderCreateDTO orderCreateDTO) {
        log.info("添加订单：{}", orderCreateDTO);
        // 路线对象
        Route route = routeMapper.findByRouteId(orderCreateDTO.getRouteId());
        if (null==route){
            throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"路线不存在");
        }
        // 绑定的用户
        User user = userMapper.findByPhoneNumber(orderCreateDTO.getPaidUserPhoneNumber());
        if (null==user || !UserStatusEnum.ENABLE.getStatus().equals(user.getStatus())){
            throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"订单关联的用户状态异常");
        }
        // 乘客校验
        List<Passenger> passengerListByUser = passengerMapper.findBatchByUserId(user.getUserId());
        // 该用户绑定的所有乘客的(乘客电话:乘客id)映射
        Map<String,Long> passengerPhoneNumberWithIdMap = new HashMap<>();
        for (Passenger passenger : passengerListByUser) {
            passengerPhoneNumberWithIdMap.put(passenger.getPhoneNumber(),passenger.getPassengerId());
        }
        Integer businessRowStart = route.getBusinessRowStart();
        Integer businessRowEnd = route.getBusinessRowEnd();
        Integer commonRowStart = route.getCommonRowStart();
        Integer commonRowEnd = route.getCommonRowEnd();
        BigDecimal businessPrice = route.getBusinessPrice();
        BigDecimal commonPrice = route.getCommonPrice();
        List<OrderPassengerDTO> passengerList = orderCreateDTO.getPassengerList();
        // 防止同一订单的多个乘客选择同一座位
        Map<Integer,Integer> seatRowColMap = new HashMap<>();
        for (OrderPassengerDTO orderPassengerDTO : passengerList) {
            // 查看该用户是否有绑定该乘客
            if (!passengerPhoneNumberWithIdMap.containsKey(orderPassengerDTO.getPhoneNumber())){
                throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"用户未绑定乘客："+orderPassengerDTO.getPhoneNumber());
            }
            // 判断座位类型+座位行数是否符合该路线上的放票行数
            Integer seatType = orderPassengerDTO.getSeatType();
            Integer seatRowNo = orderPassengerDTO.getSeatRowNo();
            Integer seatColNo = orderPassengerDTO.getSeatColNo();
            if (SeatTypeEnum.BUSINESS.getType().equals(seatType) && (seatRowNo<businessRowStart||seatRowNo>businessRowEnd)){
                throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"商务座行号为："+businessRowStart+" 至 "+businessRowEnd);
            }
            if(SeatTypeEnum.COMMON.getType().equals(seatType) && (seatRowNo<commonRowStart||seatRowNo>commonRowEnd)){
                throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"普通座行号为："+commonRowStart+" 至 "+commonRowEnd);
            }
            // 同一订单下该座位已被选
            if (seatColNo.equals(seatRowColMap.get(seatRowNo))){
                throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"订单中存在选择相同座位的乘客");
            }
            seatRowColMap.put(seatRowNo,seatColNo);
            // 判断座位是否已被选
            Order existOrder = orderMapper.findByRouteIdAndSeatRowNoAndSeatColNoAndStatus(route.getRouteId(),seatRowNo,seatColNo,OrderStatusEnum.PAID.getStatus());
            if (null!=existOrder){
                throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"乘客座位已被选择："+orderPassengerDTO.getPhoneNumber());
            }
        }
        // 生成随机的订单编号
        String orderNum = StringUtils.generateOrderNum();
        // 为每一个乘客都生成一条订单记录
        List<Order> orderList = new ArrayList<>();
        for (OrderPassengerDTO orderPassengerDTO : passengerList) {
            Order order = new Order();
            order.setOrderNumber(orderNum);
            order.setRouteId(route.getRouteId());
            order.setPaidUserId(user.getUserId());
            order.setPassengerId(passengerPhoneNumberWithIdMap.get(orderPassengerDTO.getPhoneNumber()));
            Integer seatType =orderPassengerDTO.getSeatType();
            order.setSeatType(seatType);
            order.setSeatRowNo(orderPassengerDTO.getSeatRowNo());
            order.setSeatColNo(orderPassengerDTO.getSeatColNo());
            order.setPrice(SeatTypeEnum.BUSINESS.getType().equals(seatType)?businessPrice:commonPrice);
            order.setStatus(orderCreateDTO.getStatus());
            order.setOrderTime(orderCreateDTO.getOrderTime());
            orderList.add(order);
        }
        // 批量插入
        orderMapper.insertBatch(orderList);
    }

    /**
     * 修改订单
     * @param orderUpdateDTO
     */
    @Override
    public void updateOrder(OrderUpdateDTO orderUpdateDTO) {
        log.info("修改订单：{}",orderUpdateDTO);
        // 订单是否存在
        Order existOrder = orderMapper.findByOrderId(orderUpdateDTO.getOrderId());
        if (null==existOrder){
            throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"订单信息异常");
        }
        // 路线对象
        Route route = routeMapper.findByRouteId(orderUpdateDTO.getRouteId());
        if (null==route){
            throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"路线不存在");
        }
        // 绑定的用户
        User user = userMapper.findByPhoneNumber(orderUpdateDTO.getPaidUserPhoneNumber());
        if (null==user || !UserStatusEnum.ENABLE.getStatus().equals(user.getStatus())){
            throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"订单关联的用户状态异常");
        }
        // 乘客
        Passenger passengerWithUser = passengerMapper.findByPhoneNumberAndUserId(orderUpdateDTO.getPassengerPhoneNumber(), user.getUserId());
        if (null==passengerWithUser){
            throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"用户未绑定该乘客");
        }
        // 判断修改的座位是否符合路线座位
        Integer businessRowStart = route.getBusinessRowStart();
        Integer businessRowEnd = route.getBusinessRowEnd();
        Integer commonRowStart = route.getCommonRowStart();
        Integer commonRowEnd = route.getCommonRowEnd();
        Integer seatType = orderUpdateDTO.getSeatType();
        Integer seatRowNo = orderUpdateDTO.getSeatRowNo();
        Integer seatColNo = orderUpdateDTO.getSeatColNo();
        if (SeatTypeEnum.BUSINESS.getType().equals(seatType) && (seatRowNo<businessRowStart || seatRowNo>businessRowEnd)){
            throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"商务座行号为："+businessRowStart+" 至 "+businessRowEnd);
        }
        if(SeatTypeEnum.COMMON.getType().equals(seatType) && (seatRowNo<commonRowStart||seatRowNo>commonRowEnd)){
            throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"普通座行号为："+commonRowStart+" 至 "+commonRowEnd);
        }
        // 判断座位是否已被选
        Order existSeat = orderMapper.findByRouteIdAndSeatRowNoAndSeatColNoAndStatus(route.getRouteId(), seatRowNo, seatColNo, OrderStatusEnum.PAID.getStatus());
        if (null!=existSeat && !existSeat.getOrderId().equals(orderUpdateDTO.getOrderId())){
            throw new BaseException(ResponseCodeEnum.CODE_400.getCode(),"乘客座位已被选择");
        }

        Order order = new Order();
        BeanUtils.copyProperties(orderUpdateDTO,order);
        order.setPaidUserId(user.getUserId());
        order.setPassengerId(passengerWithUser.getPassengerId());
        orderMapper.update(order);
    }

    /**
     * 删除订单
     * @param orderId
     */
    @Override
    public void deleteOrder(Long orderId) {
        log.info("删除订单：orderId={}",orderId);
        orderMapper.deleteByOrderId(orderId);
    }

    /**
     * 导出订单
     * @param orderVOList
     * @param response
     */
    @Override
    public void exportOrderExcel(List<OrderVO> orderVOList, HttpServletResponse response) {
        log.info("订单：导出excel表");
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("template/订单报表.xlsx");
        try{
            XSSFWorkbook excel = new XSSFWorkbook(inputStream);
            XSSFSheet sheet = excel.getSheet("Sheet1");
            for(int i=1;i<=orderVOList.size();i++){
                XSSFRow xssfRow = sheet.createRow(i);
                for(int j=0;j<11;j++){
                    xssfRow.createCell(j);
                }
            }
            for(int i=0;i<orderVOList.size();i++){
                OrderVO orderVO = orderVOList.get(i);
                XSSFRow row = sheet.getRow(i + 1);
                row.getCell(0).setCellValue(orderVO.getOrderId());
                row.getCell(1).setCellValue(orderVO.getOrderNumber());
                row.getCell(2).setCellValue(orderVO.getRouteId());
                row.getCell(3).setCellValue(orderVO.getPassengerPhoneNumber());
                row.getCell(4).setCellValue(SeatTypeEnum.getByType(orderVO.getSeatType()).getDescription());
                row.getCell(5).setCellValue(orderVO.getSeatRowNo());
                row.getCell(6).setCellValue(orderVO.getSeatColNo());
                row.getCell(7).setCellValue(orderVO.getPaidUserPhoneNumber());
                row.getCell(8).setCellValue(orderVO.getPrice().setScale(2, BigDecimal.ROUND_HALF_UP).toString());
                row.getCell(9).setCellValue(String.valueOf(orderVO.getOrderTime()));
                row.getCell(10).setCellValue(OrderStatusEnum.getByStatus(orderVO.getStatus()).getDescription());
            }
            ServletOutputStream outputStream = response.getOutputStream();
            excel.write(outputStream);
            excel.close();
            inputStream.close();
        }catch (Exception e){
            log.error("订单导出excel表异常",e);
            throw new BaseException(ResponseCodeEnum.CODE_500);

        }
    }

    /**
     * 统计订单数量
     * @param orderStatisticDTO
     * @return
     */
    @Override
    public OrderStatisticNumVO orderNumStatistic(OrderStatisticDTO orderStatisticDTO) {
        log.info("统计订单数量：{}",orderStatisticDTO);
        LocalDate orderTimeStart = orderStatisticDTO.getOrderTimeStart();
        LocalDate orderTimeEnd = orderStatisticDTO.getOrderTimeEnd();
        LocalDate nowLocalDate = LocalDate.now();
        if (null==orderTimeStart){
            orderTimeStart = nowLocalDate;
        }
        if (null==orderTimeEnd){
            // 默认统计7天内数据
            orderTimeEnd = nowLocalDate.plusDays(7);
        }
        List<LocalDate> dateList = new ArrayList<>();
        List<String> xDateList = new ArrayList<>();
        List<Integer> yDataList = new ArrayList<>();
        while (!orderTimeStart.equals(orderTimeEnd)){
            dateList.add(orderTimeStart);
            orderTimeStart = orderTimeStart.plusDays(1);
        }
        dateList.add(orderTimeStart);
        // 统计每日有效订单数量
        for (LocalDate localDate : dateList) {
            LocalDateTime beginDateTime = LocalDateTime.of(localDate, LocalTime.MIN);
            LocalDateTime endDateTime = LocalDateTime.of(localDate, LocalTime.MAX);
            Integer count = orderMapper.countOrderNumberByDateAndStatus(beginDateTime,endDateTime,OrderStatusEnum.PAID.getStatus());
            xDateList.add(localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            yDataList.add(count);
        }
        OrderStatisticNumVO orderStatisticNumVO = new OrderStatisticNumVO();
        orderStatisticNumVO.setXDateList(xDateList);
        orderStatisticNumVO.setYDataList(yDataList);
        return orderStatisticNumVO;
    }


    /**
     * 统计订单金额
     * @param orderStatisticDTO
     * @return
     */
    @Override
    public OrderStatisticMoneyVO orderMoneyStatistic(OrderStatisticDTO orderStatisticDTO) {
        log.info("统计订单金额：{}",orderStatisticDTO);
        LocalDate orderTimeStart = orderStatisticDTO.getOrderTimeStart();
        LocalDate orderTimeEnd = orderStatisticDTO.getOrderTimeEnd();
        LocalDate nowLocalDate = LocalDate.now();
        if (null==orderTimeStart){
            orderTimeStart = nowLocalDate;
        }
        if (null==orderTimeEnd){
            // 默认统计7天内数据
            orderTimeEnd = nowLocalDate.plusDays(7);
        }
        List<LocalDate> dateList = new ArrayList<>();
        List<String> xDateList = new ArrayList<>();
        List<Float> yDataList = new ArrayList<>();
        while (!orderTimeStart.equals(orderTimeEnd)){
            dateList.add(orderTimeStart);
            orderTimeStart = orderTimeStart.plusDays(1);
        }
        dateList.add(orderTimeStart);
        // 统计每日有效订单数量
        for (LocalDate localDate : dateList) {
            LocalDateTime beginDateTime = LocalDateTime.of(localDate, LocalTime.MIN);
            LocalDateTime endDateTime = LocalDateTime.of(localDate, LocalTime.MAX);
            BigDecimal price = orderMapper.countOrderPriceByDateAndStatus(beginDateTime,endDateTime,OrderStatusEnum.PAID.getStatus());
            xDateList.add(localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            if (price==null){
                yDataList.add((float) 0);
            }else{
                yDataList.add(price.setScale(2, BigDecimal.ROUND_HALF_UP).floatValue() );
            }
        }
        OrderStatisticMoneyVO orderStatisticMoneyVO = new OrderStatisticMoneyVO();
        orderStatisticMoneyVO.setXDateList(xDateList);
        orderStatisticMoneyVO.setYDataList(yDataList);
        return orderStatisticMoneyVO;
    }
}
